iT邦幫忙

2024 iThome 鐵人賽

DAY 25
0

Mockito中常用的方法

  • when().thenReturn()
    在測試方法中,when()用來指定測試的方法需要進行哪些動作,通常會先調用目標方法然後將返回值回傳給when() (此步驟稱為打樁程序 Stub)
    此方法可以應用在需要呼叫外部API的測試方法中,測試方法可以呼叫目標方法然後給定一個預定的值。
when(目標方法).thenReturn(調用目標方法後自定義的返回值)
Mockito.when(studentService.getStudentScore(Mockito.anyString())).thenReturn(.getStudentScoreInfo());
  • doReturn().when()
    和when().thenReturn()的方法是類似的,但doReturn().when()不會實際呼叫目標方法。
    舉例來說,使用when().thenReturn()模擬呼叫外部API,假設找不到該API的子路徑,此方法可能會發生NullPointException,因為在when()內實際呼叫了此方法。而doReturn().when()則反之。

小結:when().thenReturn()會實際呼叫目標方法(成功)後返回自定義值;doReturn().when()會自定義呼叫目標方法的返回值,但不會實際執行目標方法。

  • callRealMethod()
    即使受測 Service 被 Mock 了,我們還是可以透過 callRealMethod 方法呼叫真實的方法並返回實際值。
  • assertEquals(expected,actual)
    用來驗證兩值是否相等。
assertEquals("預計結果","實際結果")
assertEquals("85",actualAverageScore)

實作範例

假設今天老師想要計算學生考試的平均成績,為此我們設計了一個 calculAverageScore 方法用於計算學生平均成績。我們可以透過 Unit Test 的方式來驗證此方法的業務邏輯是否正確,不需要實際去取得資料庫中學生的分數。

受測 Service 如下:

@Service("StudentService")
public class StudentService {

    private StudentInformationRepository studentInformationRepository;
    private StudentScoresRepository studentScoresRepository;

    @Autowired
    public StudentService(StudentInformationRepository studentInformationRepository,
                          StudentScoresRepository studentScoresRepository) {
        this.studentInformationRepository = studentInformationRepository;
        this.studentScoresRepository = studentScoresRepository;
    }

    public float calculAverageScore(List<StudentScores> studentScoreList){

        int totalScore = studentScoreList.stream()
                .mapToInt(studentScore -> Integer.parseInt(studentScore.getSsScore()))
                .sum();

        return (float) totalScore / studentScoreList.size();
    }

Unit Test 如下:

@SpringBootTest
@ExtendWith(MockitoExtension.class)
class DemoApplicationTests {

    @Spy
    @InjectMocks
    private StudentService studentService;

    @BeforeEach
    public void initMocks() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void calculAverageScoreTest(){

        doReturn(getStudentScoresList()).when(studentService).getStudentScoresBySerialNumber(Mockito.anyString());

        List<StudentScores> studentScoresList = studentService.getStudentScoresBySerialNumber("113A3G0006");
        float actualAverageScore = studentService.calculAverageScore(studentScoresList);

        float expectedAverage = (100 + 75 + 85) / studentScoresList.size();

        // 進行 assert,檢查平均分數是否正確
        assertEquals(expectedAverage, actualAverageScore, 1f); // 允許少量誤差

    }

    public List<StudentScores> getStudentScoresList(){

        List<StudentScores> studentScoresList = new ArrayList<>();

        studentScoresList.add(createStudentScore(115, "Math", "113-1", "100"));
        studentScoresList.add(createStudentScore(115, "EnglishLanguage", "113-1", "75"));
        studentScoresList.add(createStudentScore(115, "ChineseLanguage", "113-1", "85"));

        return studentScoresList;
    }

    private StudentScores createStudentScore(int siId, String subject, String examId, String score) {
        StudentScores studentScore = new StudentScores();
        studentScore.setSsSiId(siId);
        studentScore.setSsSubject(subject);
        studentScore.setSsExamId(examId);
        studentScore.setSsScore(score);
        return studentScore;
    }
}

此支單元測試方法為了驗證 StudentService 中的 calculAverageScore 方法,為了不讓程式實際執行資料庫查詢操作,我們透過 getStudentScoresList 方法模擬學生的成績資料。並藉由 doReturn 方法將 getStudentScoresList 方法內模擬的資料返回。

assertEquals 中的第三個參數表示的是”允許的誤差範圍”,這對於處理浮點數資料的判斷比較重要。


上一篇
Day24 - JUnit單元測試(上)
下一篇
Day26 - Spring Boot 整合 RabbitMQ(上)
系列文
這些年SpringBoot實戰開發教會我的事30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言